package au.edu.unsw.editingtool.web;

import java.io.IOException;
import java.io.PrintWriter;
import java.sql.SQLException;
import java.util.Enumeration;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.RequestDispatcher;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpServletResponse;

import au.edu.unsw.editingtool.db.DBSession;
import au.edu.unsw.editingtool.global.EditingToolException;
import au.edu.unsw.editingtool.global.GlobalConstant;
import au.edu.unsw.editingtool.global.SessionBindingListener;

/**
 * Servlet Filter implementation class WebFilter
 */
public class WebFilter implements Filter {

    /**
     * Default constructor. 
     */
	private FilterConfig filterConfig = null;
	private String ServletContext = null;
	private String ApplicationContext = null;
	private String ApplicationPath = null;
	
    public WebFilter() {
        // TODO Auto-generated constructor stub
    }

	/**
	 * @see Filter#destroy()
	 */
	public void destroy() {
		// TODO Auto-generated method stub
	}

	/**
	 * @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
	 */
	public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
		ApplicationContext = request.getLocalName()+":"+request.getServerPort()+"/"+
		GlobalConstant.APPLICATIONNAME+"/";
		ApplicationPath = ((HttpServletRequest)request).getContextPath();
		System.out.println("==== [WEBFILTER] WebFilter in action ====");
		HttpSession session = ((HttpServletRequest)request).getSession(); 
		
		//System.out.println("[WEBFILTER] ApplicationContext = "+this.ApplicationContext);
		//System.out.println("[WEBFILTER] ApplicationPath = "+this.ApplicationPath);
		//System.out.println("[WEBFILTER] servletContext = "+this.ServletContext);
		
		String username = null;
		String sid= null;
		String sessionid = null;
		String querystring="";
		
		querystring = (String) ((HttpServletRequest)request).getQueryString();
		if(querystring==null)
			querystring="";
		
		System.out.println("[WEBFILTER] Querystring : "+querystring);
		
		// If it is a new session, redirect to login.
		username = (String) session.getAttribute("username");
		sid = (String) session.getAttribute("sid");
		sessionid = session.getId();
		
		if (session.isNew() )
		{	
			if (username == null || sid==null || username.length()==0 || sid.length()==0)
			{	
				String ctrl = (String) request.getParameter(GlobalConstant.requestCommand);
				if(ctrl==null)
					ctrl="";
				
				session.setAttribute(GlobalConstant.username, GlobalConstant.userAnonymous);
				session.setAttribute(GlobalConstant.sid, "0");			
				System.out.println("[WEBFILTER] No user information on the session!");
				if(ctrl.compareTo(GlobalConstant.cmdClaimStatusUpdate)==0 || ctrl.compareTo(GlobalConstant.cmdClaimDelete)==0)
				{
					PrintWriter out = response.getWriter();
					out.println("ERROR: 1["+ctrl+"] Session has expired!");
					return;
				}
				else
				{
					System.out.println("[WEBFILTER] forward to "+GlobalConstant.JSPLogin);
					RequestDispatcher rd = request.getRequestDispatcher(GlobalConstant.JSPLogin+"?"+querystring);
					rd.forward(request, response);
					return;
				}
			}
			/*
			String ctrl = (String) request.getParameter(GlobalConstant.requestCommand);
			if(ctrl==null)
				ctrl="";
			session.setAttribute(GlobalConstant.username, GlobalConstant.userAnonymous);
			session.setAttribute(GlobalConstant.sid, "0");	
			System.out.println("[WEBFILTER] New Session");	
			
			if(ctrl.compareTo(GlobalConstant.cmdClaimStatusUpdate)==0 || ctrl.compareTo(GlobalConstant.cmdClaimDelete)==0)
			{
				PrintWriter out = response.getWriter();
				out.println("ERROR: ["+ctrl+"] Session has expired!");
				return;
			}
			else
			{
				System.out.println("[WEBFILTER] forward to "+GlobalConstant.JSPLogin);			
				RequestDispatcher rd = request.getRequestDispatcher(GlobalConstant.JSPLogin+"?"+querystring);
				rd.forward(request, response);			
				return;
			}*/
		}
		
		// If login is not valid from session table
		if(!this.isLoginValid(sid,sessionid,username))
		{			
			LogoutManager.clearSession(session);
			request.setAttribute(GlobalConstant.responseType,GlobalConstant.typeError);
			request.setAttribute(GlobalConstant.responseMsg, "Error! You need to login to continue!");
			
			Enumeration paramKeys = request.getParameterNames();			
			while(paramKeys.hasMoreElements())
			{
				String paramKey = paramKeys.nextElement().toString();
				request.setAttribute(paramKey, request.getParameter(paramKey));
			}
			
			String ctrl = (String) request.getParameter(GlobalConstant.requestCommand);
			if(ctrl==null)
				ctrl="";
			
			System.out.println("[WEBFILTER] Not login yet or session has expired!");
			if(ctrl.compareTo(GlobalConstant.cmdClaimStatusUpdate)==0 || ctrl.compareTo(GlobalConstant.cmdClaimDelete)==0)
			{
				PrintWriter out = response.getWriter();
				out.println("ERROR: 2["+ctrl+"] Session has expired!");
				return;
			}
			else
			{
				System.out.println("[WEBFILTER] forward to "+GlobalConstant.JSPLogin);
				RequestDispatcher rd = request.getRequestDispatcher(GlobalConstant.JSPLogin+"?"+querystring);
				rd.forward(request, response);
				return;
			}
		}	
	
		// Auto clean session table.
		// 1. Grab all data on session table based on the username.
		// 2. Check the date compare with the current date based on the timeout.
		// 3. Delete the one that has exceeded the timeout.
		String lastaccesstime = ((Long) session.getLastAccessedTime()).toString();
		if(Integer.parseInt(sid)!=0)
		{
			this.updateLastAccessTime(sid, lastaccesstime); 
		}
		int sessionresult = this.cleanUserSession(sid, sessionid, username);		
				
		// Update SessionBindingListener information;
		if(session.getAttribute("sessionlistener")==null)
		{
			System.out.println("[WEBFILTER] SESSIONBINDINGLISTENER is added!");
			SessionBindingListener sbl = new SessionBindingListener(ServletContext,username,sessionid,sid);
			session.setAttribute("sessionlistener",sbl);
		}		
		//TODO
		// 4. Update log table.
		System.out.println("[WEBFILTER] User is VALID, Process Continue.........");	
		chain.doFilter(request, response);
	}
	
	/*
	 * Check the user is valid
	 */
	private boolean isLoginValid(String csid, String csessionid, String cusername)
	{	
		boolean result = false;
		if (csid==null || csid.length()==0 || csessionid==null || csessionid.length() == 0 || cusername==null || cusername.length()==0)
		{
			return result;
		}
						
		DBSession dbsession = new DBSession();
		dbsession.setConfFile(ServletContext + GlobalConstant.configFilePath);
		
		try {
			result = dbsession.isLoginValid(csid, csessionid, cusername);
		} 
		catch (Exception e) {			
			e.printStackTrace();
		}		
		return result;
	}
	
	/*
	 *  Update Last Access Time on the sid
	 */	
	private void updateLastAccessTime(String csid, String clastaccesstime)
	{
		if (csid==null || csid.length()==0 || clastaccesstime == null || clastaccesstime.length()==0)
		{
			return;
		}
		DBSession dbsession = new DBSession();
		dbsession.setConfFile(ServletContext + GlobalConstant.configFilePath);
		try {
			dbsession.updateLastAccessTime(csid, clastaccesstime);
		} 
		catch (Exception e) {			
			e.printStackTrace();
		}		
		
	}
	
	/* 
	 * Auto clean session table for current user
	 */
	private int cleanUserSession(String csid, String csessionid, String cusername)
	{
		int result = 0;
		if (csid==null || csid.length()==0 || csessionid==null || csessionid.length() == 0 || cusername==null || cusername.length()==0)
		{
			return result;
		}
		DBSession dbsession = new DBSession();
		dbsession.setConfFile(ServletContext + GlobalConstant.configFilePath);
		try {
			result = dbsession.cleanUserSession(csid, csessionid, cusername);
		} 
		catch (Exception e) {			
			e.printStackTrace();
		}		
		return result;
	}
	
	
	/**
	 * @see Filter#init(FilterConfig)
	 */
	public void init(FilterConfig fConfig) throws ServletException 
	{
		this.filterConfig = fConfig;		
		ServletContext = fConfig.getServletContext().getRealPath("") + GlobalConstant.fileSeparator;
		//System.out.println("[WEBFILTER] ServletContext : "+ServletContext);
	}
	
	public FilterConfig getFilterConfig()
	{
        	return filterConfig;
	}

}
